home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / wu-ftpd-.000 / wu-ftpd- / wu-ftpd-2.4-fixed / support / sco.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-01  |  19.6 KB  |  724 lines

  1. /* Written in 1992, 1993 by Eduard Vopicka, Prague University of Economics */
  2.  
  3. #include "../src/config.h"
  4.  
  5. #include <sys/types.h>
  6. #include <stdio.h>
  7. #include <fcntl.h>
  8. #include <sys/immu.h>
  9. #include <sys/dir.h>        /* required by <sys/user.h> */
  10. #include <sys/user.h>
  11. #include <sys/signal.h>
  12. #include <sys/fs/s5param.h>
  13. #include <string.h>
  14. #include <syslog.h>
  15. #include <sys/stat.h>
  16. #include <varargs.h>
  17.  
  18. static int KmemFd = -1;
  19.  
  20. kmem_open()
  21. {
  22.     if (KmemFd < 0 && (KmemFd = open("/dev/kmem", O_RDWR, 0)) < 0) {
  23.         syslog(LOG_EMERG, "kmem open failed: %m");
  24.         exit(1);
  25.     }
  26. }
  27.  
  28. int
  29. wrub(addr, off, len)
  30.     char    *addr;
  31.     off_t   off;
  32.     int len;
  33. {
  34.     off_t seek_off = UVUBLK+off;
  35.     kmem_open();                /* make sure it is open */
  36.     if (lseek(KmemFd, (char*)seek_off, SEEK_SET) != seek_off) {
  37.         syslog(LOG_EMERG, "lseek failed on /dev/kmem: %m");
  38.         exit(1);
  39.     }
  40.     if (write(KmemFd, addr, len) != len) {
  41.         syslog(LOG_EMERG, "write failed on /dev/kmem: %m");
  42.         exit(1);
  43.     }
  44.     return(0);
  45. }
  46.  
  47. void
  48. s5proctitle(s)
  49.     char    *s;
  50. {
  51.     struct user u;
  52.     char buf[PSARGSZ];
  53.     int len = strlen(s);
  54.     if (len >= PSARGSZ) len = PSARGSZ-1;
  55.     strncpy(buf,s,len);
  56.     buf[len] = '\0';
  57.     wrub(buf, (off_t)u.u_psargs-(off_t)&u, PSARGSZ);
  58. }
  59.  
  60. /* #ifndef _M_UNIX     /* before 3.2v4.0 */
  61. /* UHUHUH, this crazy code is still required for 3.2v4.2 */
  62.  
  63. uid_t
  64. seteuid(id)
  65.     uid_t   id;
  66. {
  67.     struct  user u;
  68.     return(wrub(&id, (off_t)&u.u_uid-(off_t)&u, sizeof(id)));
  69. }
  70.  
  71. uid_t
  72. setruid(id)
  73.     uid_t   id;
  74. {
  75.     struct  user u;
  76.     return(wrub(&id, (off_t)&u.u_ruid-(off_t)&u, sizeof(id)));
  77. }
  78.  
  79.  
  80. uid_t
  81. setegid(id)
  82.     uid_t   id;
  83. {
  84.     struct  user u;
  85.     return(wrub(&id, (off_t)&u.u_gid-(off_t)&u, sizeof(id)));
  86. }
  87.  
  88. uid_t
  89. setrgid(id)
  90.     uid_t   id;
  91. {
  92.     struct  user u;
  93.     return(wrub(&id, (off_t)&u.u_rgid-(off_t)&u, sizeof(id)));
  94. }
  95.  
  96. uid_t
  97. setuid(id)
  98.     uid_t   id;
  99. {
  100.     (void)seteuid(id);
  101.     (void)setruid(id);
  102.     return(0);
  103. }
  104.  
  105. uid_t
  106. setgid(id)
  107.     uid_t   id;
  108. {
  109.     (void)setegid(id);
  110.     (void)setrgid(id);
  111.     return(0);
  112. }
  113.  
  114. uid_t
  115. setreuid(ruid, euid)
  116.     uid_t   ruid, euid;
  117. {
  118.     if (ruid != 0xffff)
  119.         (void)setruid(ruid);
  120.     if (euid != 0xffff)
  121.         (void)seteuid(euid);
  122.     return(0);
  123. }
  124. /* #endif /* _M_UNIX */
  125.  
  126. #ifdef SETPROCTITLE
  127.  
  128. void
  129. SCOproctitle(va_alist)
  130.     va_dcl
  131. {
  132.     va_list ap;
  133.     char *fmt;
  134.  
  135.     register char *p;
  136.     char buf[BUFSIZ];
  137.  
  138.     va_start(ap);
  139.     fmt = va_arg(ap, char *); /* first argument is always the fmt string */
  140.     p = buf; *p++ = '-'; p += vsprintf(p, fmt, ap);
  141.     va_end(ap)
  142.  
  143.     while (*--p == '\r' || *p == '\n' || *p == ' ' || *p == '\t');
  144.     p = strcpy(++p, " (ftpd)"); /* make ps print our process name */
  145. /*  while (*p) p++; */
  146.     s5proctitle(buf);
  147. }
  148. #endif /* SETPROCTITLE */
  149.  
  150. /*
  151.  * Copyright (c) 1989, 1991 The Regents of the University of California.
  152.  * All rights reserved.
  153.  *
  154.  * Redistribution and use in source and binary forms, with or without
  155.  * modification, are permitted provided that the following conditions
  156.  * are met:
  157.  * 1. Redistributions of source code must retain the above copyright
  158.  *    notice, this list of conditions and the following disclaimer.
  159.  * 2. Redistributions in binary form must reproduce the above copyright
  160.  *    notice, this list of conditions and the following disclaimer in the
  161.  *    documentation and/or other materials provided with the distribution.
  162.  * 3. All advertising materials mentioning features or use of this software
  163.  *    must display the following acknowledgement:
  164.  *  This product includes software developed by the University of
  165.  *  California, Berkeley and its contributors.
  166.  * 4. Neither the name of the University nor the names of its contributors
  167.  *    may be used to endorse or promote products derived from this software
  168.  *    without specific prior written permission.
  169.  *
  170.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  171.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  172.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  173.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  174.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  175.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  176.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  177.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  178.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  179.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  180.  * SUCH DAMAGE.
  181.  */
  182.  
  183. #if defined(SYSLOGFILE)
  184.  
  185. #include <sys/types.h>
  186. #include <sys/file.h>
  187. #include <sys/signal.h>
  188. #include <sys/syslog.h>
  189. #include <sys/uio.h>
  190. #include <fcntl.h>
  191. #include <varargs.h>
  192. #include <stdio.h>
  193. #include <string.h>
  194. #include <strings.h>
  195.  
  196. #ifndef CONSOLE
  197. # define CONSOLE "/dev/console"
  198. #endif
  199.  
  200. static int  LogFile = -1;       /* fd for log */
  201. static int  LogStat = 0;        /* status bits, set by openlog() */
  202. static char *LogTag = "syslog"; /* string to tag the entry with */
  203. static int  LogFacility = LOG_USER; /* default facility code */
  204. static int  LogMask = 0xff;     /* mask of priorities to be logged */
  205.  
  206. syslog(va_alist)
  207.     va_dcl
  208. {
  209.     va_list args;
  210.     int pri;
  211.     char *fmt;
  212.  
  213.     va_start(args);
  214.  
  215.     pri = va_arg(args, int);
  216.     fmt = va_arg(args, char *);
  217.  
  218.     vsyslog(pri, fmt, args);
  219.  
  220.     va_end(args);
  221. }
  222.  
  223. vsyslog(pri, fmt, ap)
  224.     int pri;
  225.     register char *fmt;
  226.     va_list ap;
  227. {
  228.     extern int errno;
  229.     register int cnt;
  230.     register char *p;
  231.     time_t now, time();
  232.     int pid, saved_errno;
  233.     char tbuf[2048], fmt_cpy[1024], *stdp, *ctime();
  234.  
  235.     sigset_t newmask, oldmask;
  236.  
  237.     saved_errno = errno;
  238.  
  239. #ifndef LOG_FAC
  240. #define LOG_FAC(pri)    (((pri) & LOG_FACMASK) >> 3)
  241. #endif
  242. #ifndef LOG_PRI
  243. #define LOG_PRI(pri)    ((pri) & LOG_PRIMASK)
  244. #endif
  245.  
  246.     /* see if we should just throw out this message */
  247.     if ((u_int)LOG_FAC(pri) >= (1 << LOG_NFACILITIES) ||
  248.         (!(LOG_MASK(LOG_PRI(pri))&LogMask)) ||
  249.         (pri &~ (LOG_PRIMASK|LOG_FACMASK)))
  250.         return;
  251.     if (LogFile < 0)
  252.         openlog(LogTag, LogStat | LOG_NDELAY, 0);
  253.  
  254.     /* set default facility if none specified */
  255.     if ((pri & LOG_FACMASK) == 0)
  256.         pri |= LogFacility;
  257.  
  258.     /* build the message */
  259.     (void)time(&now);
  260.     (void)sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4); /**/
  261. /*  (void)sprintf(tbuf, "%3o %.15s ", pri, ctime(&now) + 4); /**/
  262.     for (p = tbuf; *p; ++p);
  263. #ifndef LOG_PERROR
  264. #define LOG_PERROR 0x20
  265. #endif
  266.     if (LogStat & LOG_PERROR)
  267.         stdp = p;
  268.     if (LogTag) {
  269.         (void)strcpy(p, LogTag);
  270.         for (; *p; ++p);
  271.     }
  272.     if (LogStat & LOG_PID) {
  273.         (void)sprintf(p, "[%d]", getpid());
  274.         for (; *p; ++p);
  275.     }
  276.     if (LogTag) {
  277.         *p++ = ':';
  278.         *p++ = ' ';
  279.     }
  280.  
  281.     /* substitute error message for %m */
  282.     {
  283.         register char ch, *t1, *t2;
  284. /*      char *strerror(); /**/
  285.  
  286.         for (t1 = fmt_cpy; ch = *fmt; ++fmt)
  287.             if (ch == '%' && fmt[1] == 'm') {
  288.                 ++fmt;
  289.                 for (t2 = strerror(saved_errno);
  290.                     *t1 = *t2++; ++t1);
  291.             }
  292.             else
  293.                 *t1++ = ch;
  294.         *t1 = '\0';
  295.     }
  296.  
  297.     (void)vsprintf(p, fmt_cpy, ap);
  298.  
  299.     cnt = strlen(tbuf);
  300.     tbuf[cnt++]='\n';
  301.  
  302.     /* output to stderr if requested */
  303.     if (LogStat & LOG_PERROR)
  304.         write(2, stdp, cnt - (stdp - tbuf));
  305.  
  306.     /* output the message to the local logger */
  307.     if (write(LogFile, tbuf, cnt) == cnt)
  308.         return;
  309.  
  310.     /* output the message to the console */
  311.     pid = vfork();
  312.     if (pid == -1)
  313.         return;
  314.     if (pid == 0) {
  315.         int fd;
  316.  
  317.         sigfillset(&newmask); sigdelset(&newmask, SIGALRM);
  318.         (void) sigprocmask(SIG_SETMASK, &newmask, &oldmask);
  319.         (void)signal(SIGALRM, SIG_DFL);
  320.         (void)alarm((u_int)5);
  321.         if ((fd = open(CONSOLE, O_WRONLY, 0)) < 0)
  322.             return;
  323.         (void)alarm((u_int)0);
  324.         (void)strcat(tbuf, "\r");
  325.         p = index(tbuf, '>') + 1;
  326.         (void)write(fd, p, cnt + 1 - (p - tbuf));
  327.         (void)close(fd);
  328.         _exit(0);
  329.     }
  330.     if (!(LogStat & LOG_NOWAIT))
  331.         while ((cnt = wait((int *)0)) > 0 && cnt != pid);
  332. }
  333.  
  334. /*
  335.  * OPENLOG -- open system log
  336.  */
  337. openlog(ident, logstat, logfac)
  338.     char *ident;
  339.     int logstat, logfac;
  340. {
  341.     if (ident != NULL)
  342.         LogTag = ident;
  343.     LogStat = logstat;
  344.     if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
  345.         LogFacility = logfac;
  346.     if (LogFile == -1) {
  347.         LogFile = open(SYSLOGFILE, O_WRONLY|O_APPEND|O_SYNC);   /**/
  348. /*      LogFile = open(SYSLOGFILE, O_WRONLY|O_APPEND);      /**/
  349.     }
  350. }
  351.  
  352. /*
  353.  * CLOSELOG -- close the system log
  354.  */
  355. closelog()
  356. {
  357.     (void) close(LogFile);
  358.     LogFile = -1;
  359. }
  360.  
  361. /*
  362.  * SETLOGMASK -- set the log mask level
  363.  */
  364. setlogmask(pmask)
  365.     int pmask;
  366. {
  367.     int omask;
  368.  
  369.     omask = LogMask;
  370.     if (pmask != 0)
  371.         LogMask = pmask;
  372.     return (omask);
  373. }
  374.  
  375. #endif /* defined(SYSLOGFILE) */
  376.  
  377. /* Need own getcwd() because of the way getcwd is implemented in SCO UNIX */
  378.  
  379. /*
  380.  * Copyright (c) 1989, 1991 The Regents of the University of California.
  381.  * All rights reserved.
  382.  *
  383.  * Redistribution and use in source and binary forms, with or without
  384.  * modification, are permitted provided that the following conditions
  385.  * are met:
  386.  * 1. Redistributions of source code must retain the above copyright
  387.  *    notice, this list of conditions and the following disclaimer.
  388.  * 2. Redistributions in binary form must reproduce the above copyright
  389.  *    notice, this list of conditions and the following disclaimer in the
  390.  *    documentation and/or other materials provided with the distribution.
  391.  * 3. All advertising materials mentioning features or use of this software
  392.  *    must display the following acknowledgement:
  393.  *  This product includes software developed by the University of
  394.  *  California, Berkeley and its contributors.
  395.  * 4. Neither the name of the University nor the names of its contributors
  396.  *    may be used to endorse or promote products derived from this software
  397.  *    without specific prior written permission.
  398.  *
  399.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  400.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  401.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  402.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  403.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  404.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  405.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  406.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  407.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  408.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  409.  * SUCH DAMAGE.
  410.  */
  411.  
  412. #if defined(LIBC_SCCS) && !defined(lint)
  413. static char sccsid[] = "@(#)getcwd.c    5.11 (Berkeley) 2/24/91";
  414. #endif /* LIBC_SCCS and not lint */
  415.  
  416. #include <sys/param.h>
  417.  
  418. #ifndef HAVE_SYMLINK
  419. # define lstat stat
  420. #endif
  421.  
  422. #include <sys/stat.h>
  423. #include <errno.h>
  424. #include <dirent.h>
  425. #include <stdio.h>
  426. #include <string.h>
  427.  
  428. #ifdef HAVE_D_NAMLEN
  429. # define DNAMLEN(dp) (dp->d_namlen)
  430. #else
  431. # define DNAMLEN(dp) (strlen(dp->d_name))
  432. #endif
  433.  
  434. #define ISDOT(dp) \
  435.     (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
  436.         dp->d_name[1] == '.' && dp->d_name[2] == '\0'))
  437.  
  438. char *
  439. getcwd(pt, size)
  440.     char *pt;
  441.     int size;
  442. {
  443.     register struct dirent *dp;
  444.     register DIR *dir;
  445.     register dev_t dev;
  446.     register ino_t ino;
  447.     register int first;
  448.     register char *bpt, *bup;
  449.     struct stat s;
  450.     dev_t root_dev;
  451.     ino_t root_ino;
  452.     size_t ptsize, upsize;
  453.     int save_errno;
  454.     char *ept, *eup, *up, *ptr;
  455.  
  456.     /*
  457.      * If no buffer specified by the user, allocate one as necessary.
  458.      * If a buffer is specified, the size has to be non-zero.  The path
  459.      * is built from the end of the buffer backwards.
  460.      */
  461.     if (pt) {
  462.         ptsize = 0;
  463.         if (!size) {
  464.             errno = EINVAL;
  465.             return((char *)NULL);
  466.         }
  467.         ept = pt + size;
  468.     } else {
  469.         if (!(pt = (char *)malloc(ptsize = 1024 - 4)))
  470.             return((char *)NULL);
  471.         ept = pt + ptsize;
  472.     }
  473.     bpt = ept - 1;
  474.     *bpt = '\0';
  475.  
  476.     /*
  477.      * Allocate bytes (1024 - malloc space) for the string of "../"'s.
  478.      * Should always be enough (it's 340 levels).  If it's not, allocate
  479.      * as necessary.  Special * case the first stat, it's ".", not "..".
  480.      */
  481.     if (!(up = (char *)malloc(upsize = 1024 - 4)))
  482.         goto err;
  483.     eup = up + MAXPATHLEN;
  484.     bup = up;
  485.     up[0] = '.';
  486.     up[1] = '\0';
  487.  
  488.     /* Save root values, so know when to stop. */
  489.     if (stat("/", &s))
  490.         goto err;
  491.     root_dev = s.st_dev;
  492.     root_ino = s.st_ino;
  493.  
  494.     errno = 0;          /* XXX readdir has no error return. */
  495.  
  496.     for (first = 1;; first = 0) {
  497.         /* Stat the current level. */
  498.         if (lstat(up, &s))
  499.             goto err;
  500.  
  501.         /* Save current node values. */
  502.         ino = s.st_ino;
  503.         dev = s.st_dev;
  504.  
  505.         /* Check for reaching root. */
  506.         if (root_dev == dev && root_ino == ino) {
  507.             *--bpt = '/';
  508.             /*
  509.              * It's unclear that it's a requirement to copy the
  510.              * path to the beginning of the buffer, but it's always
  511.              * been that way and stuff would probably break.
  512.              */
  513.             (void)bcopy(bpt, pt, ept - bpt);
  514.             free(up);
  515.             return(pt);
  516.         }
  517.  
  518.         /*
  519.          * Build pointer to the parent directory, allocating memory
  520.          * as necessary.  Max length is 3 for "../", the largest
  521.          * possible component name, plus a trailing NULL.
  522.          */
  523.         if (bup + 3  + MAXNAMLEN + 1 >= eup) {
  524.             off_t len = bup - up;
  525.             if (!(ptr = (char *)realloc(up, upsize *= 2)))
  526.                 goto err;
  527.             up = ptr;
  528.             bup = up + len;
  529.             eup = up + upsize;
  530.         }
  531.         *bup++ = '.';
  532.         *bup++ = '.';
  533.         *bup = '\0';
  534.  
  535.         /* Open and stat parent directory. */
  536.         if (!(dir = opendir(up)) || fstat(dir->dd_fd, &s))
  537.             goto err;
  538.  
  539.         /* Add trailing slash for next directory. */
  540.         *bup++ = '/';
  541.  
  542.         /*
  543.          * If it's a mount point, have to stat each element because
  544.          * the inode number in the directory is for the entry in the
  545.          * parent directory, not the inode number of the mounted file.
  546.          */
  547.         save_errno = 0;
  548.         if (s.st_dev == dev) {
  549.             for (;;) {
  550.                 if (!(dp = readdir(dir)))
  551.                     goto notfound;
  552.                 if (dp->d_fileno == ino)
  553.                     break;
  554.             }
  555.         } else
  556.             for (;;) {
  557.                 if (!(dp = readdir(dir)))
  558.                     goto notfound;
  559.                 if (ISDOT(dp))
  560.                     continue;
  561.                 bcopy(dp->d_name, bup, DNAMLEN(dp) + 1);
  562.  
  563.                 /* Save the first error for later. */
  564.                 if (lstat(up, &s)) {
  565.                     if (!save_errno)
  566.                         save_errno = errno;
  567.                     errno = 0;
  568.                     continue;
  569.                 }
  570.                 if (s.st_dev == dev && s.st_ino == ino)
  571.                     break;
  572.             }
  573.  
  574.         /*
  575.          * Check for length of the current name, preceding slash,
  576.          * leading slash.
  577.          */
  578.         if (bpt - pt <= DNAMLEN(dp) + (first ? 1 : 2)) {
  579.             size_t len, off;
  580.  
  581.             if (!ptsize) {
  582.                 errno = ERANGE;
  583.                 goto err;
  584.             }
  585.             off = bpt - pt;
  586.             len = ept - bpt;
  587.             if (!(ptr = (char *)realloc(pt, ptsize *= 2)))
  588.                 goto err;
  589.             pt = ptr;
  590.             bpt = pt + off;
  591.             ept = pt + ptsize;
  592.             (void)bcopy(bpt, ept - len, len);
  593.             bpt = ept - len;
  594.         }
  595.         if (!first)
  596.             *--bpt = '/';
  597.         bpt -= DNAMLEN(dp);
  598.         bcopy(dp->d_name, bpt, DNAMLEN(dp));
  599.         (void)closedir(dir);
  600.  
  601.         /* Truncate any file name. */
  602.         *bup = '\0';
  603.     }
  604.  
  605. notfound:
  606.     /*
  607.      * If readdir set errno, use it, not any saved error; otherwise,
  608.      * didn't find the current directory in its parent directory, set
  609.      * errno to ENOENT.
  610.      */
  611.     if (!errno)
  612.         errno = save_errno ? save_errno : ENOENT;
  613.     /* FALLTHROUGH */
  614. err:
  615.     if (ptsize && !pt)
  616.         free(pt);
  617.     if (!up)
  618.         free(up);
  619.     return((char *)NULL);
  620. }
  621.  
  622. char *
  623. getwd(b)
  624.     char *b;
  625. {
  626.     char *p;
  627.     uid_t euid = geteuid();
  628.     seteuid(0);
  629.     getcwd(b, MAXPATHLEN);
  630.     p = getcwd(b, MAXPATHLEN);
  631.     seteuid(euid);
  632.     return(p);
  633. }
  634.  
  635. /*
  636.  * Copyright (c) 1983 Regents of the University of California.
  637.  * All rights reserved.
  638.  *
  639.  * Redistribution and use in source and binary forms, with or without
  640.  * modification, are permitted provided that the following conditions
  641.  * are met:
  642.  * 1. Redistributions of source code must retain the above copyright
  643.  *    notice, this list of conditions and the following disclaimer.
  644.  * 2. Redistributions in binary form must reproduce the above copyright
  645.  *    notice, this list of conditions and the following disclaimer in the
  646.  *    documentation and/or other materials provided with the distribution.
  647.  * 3. All advertising materials mentioning features or use of this software
  648.  *    must display the following acknowledgement:
  649.  *  This product includes software developed by the University of
  650.  *  California, Berkeley and its contributors.
  651.  * 4. Neither the name of the University nor the names of its contributors
  652.  *    may be used to endorse or promote products derived from this software
  653.  *    without specific prior written permission.
  654.  *
  655.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  656.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  657.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  658.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  659.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  660.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  661.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  662.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  663.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  664.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  665.  * SUCH DAMAGE.
  666.  */
  667.  
  668. # if !defined(lint)
  669. static char sccsid[] = "@(#)initgroups.c    5.6 (Berkeley) 6/1/90";
  670. static char  rcsid[] = "@(#)$Id: initgroups.c,v 5.6.0.5 1992/02/23 06:56:52 paul Exp $";
  671. # endif /* !lint */
  672.  
  673. #include <stdio.h>
  674.  
  675. # include <grp.h>
  676. # ifndef NGROUPS
  677. #  ifdef NGROUPS_MAX
  678. #   define NGROUPS  NGROUPS_MAX
  679. #  else /* !NGROUPS_MAX */
  680. #   define NGROUPS  8
  681. #  endif /* NGROUPS_MAX */
  682. # endif /* !NGROUPS */
  683.  
  684. struct group *getgrent();
  685.  
  686. initgroups(uname, agroup)
  687.     char *uname;
  688.     int agroup;
  689. {
  690.     int groups[NGROUPS], ngroups = 0;
  691.     register struct group *grp;
  692.     register int i;
  693.  
  694.     /*
  695.      * If installing primary group, duplicate it;
  696.      * the first element of groups is the effective gid
  697.      * and will be overwritten when a setgid file is executed.
  698.      */
  699.     if (agroup >= 0) {
  700.         groups[ngroups++] = agroup;
  701.         groups[ngroups++] = agroup;
  702.     }
  703.     setgrent();
  704.     while (grp = getgrent()) {
  705.         if (grp->gr_gid == agroup)
  706.             continue;
  707.         for (i = 0; grp->gr_mem[i]; i++)
  708.             if (!strcmp(grp->gr_mem[i], uname)) {
  709.                 if (ngroups == NGROUPS) {
  710. fprintf(stderr, "initgroups: %s is in too many groups\n", uname);
  711.                     goto toomany;
  712.                 }
  713.                 groups[ngroups++] = grp->gr_gid;
  714.             }
  715.     }
  716. toomany:
  717.     endgrent();
  718.     if (setgroups(ngroups, groups) < 0) {
  719.         perror("setgroups");
  720.         return (-1);
  721.     }
  722.     return (0);
  723. }
  724.